Add new 'generic' xml reader, convert geo (geocaching.loc) format to use
authorrobertl <robertl@f51c46e8-681c-474f-0cfe-069cfd0219fb>
Mon, 1 Nov 2004 02:22:51 +0000 (02:22 +0000)
committerrobertl <robertl@f51c46e8-681c-474f-0cfe-069cfd0219fb>
Mon, 1 Nov 2004 02:22:51 +0000 (02:22 +0000)
it.ZZ

gpsbabel/geo.c
gpsbabel/xmlgeneric.c [new file with mode: 0644]
gpsbabel/xmlgeneric.h [new file with mode: 0644]

index 9e8eeca10af008cc95b7b389c50a95fef1daed9c..f6b4c094f652dc8fe243f422cd03d76e7b005019 100644 (file)
 
  */
 #include "defs.h"
-#if !NO_EXPAT
-#include <expat.h>
-static XML_Parser psr;
-#endif
+#include "xmlgeneric.h"
 
-static int in_wpt;
-static int in_name;
-static int in_link;
-static int in_type;
-static int in_cdata;
-static char *cdatastr;
-static char *typestr;
 static char *deficon = NULL;
 
 static waypoint *wpt_tmp;
@@ -57,185 +47,106 @@ geo_read(void)
 {
 }
 #else
-static void
-tag_coord(const char **attrv)
-{
-       const char **avp = &attrv[0];
-
-
-       while (*avp) { 
-               if (strcmp(avp[0], "lat") == 0) {
-                       sscanf(avp[1], "%lf", 
-                               &wpt_tmp->latitude);
-               }
-               else if (strcmp(avp[0], "lon") == 0) {
-                       sscanf(avp[1], "%lf", 
-                               &wpt_tmp->longitude);
-               }
-               avp+=2;
-       }
+
+static xg_callback     wpt_s, wpt_e;
+static xg_callback     wpt_link_s, wpt_link;
+static xg_callback     wpt_name, wpt_name_s, wpt_type, wpt_coord;
+
+static 
+xg_tag_mapping loc_map[] = {
+       { wpt_s,        cb_start,       "/loc/waypoint" },
+       { wpt_e,        cb_end,         "/loc/waypoint" },
+       { wpt_name_s,   cb_start,       "/loc/waypoint/name" },
+       { wpt_name,     cb_cdata,       "/loc/waypoint/name" },
+       { wpt_type,     cb_cdata,       "/loc/waypoint/type" },
+       { wpt_link_s,   cb_start,       "/loc/waypoint/link" },
+       { wpt_link,     cb_cdata,       "/loc/waypoint/link" },
+       { wpt_coord,    cb_start,       "/loc/waypoint/coord" },
+       { NULL,         0,              NULL }
+};
+
+void wpt_s(const char *args, const char **unused) 
+{ 
+//     wpt_tmp = waypt_new();
+       wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1);
 }
 
-static void
-tag_name(const char **attrv)
+void wpt_e(const char *args, const char **unused)
 {
-       const char **avp = &attrv[0];
-       while (*avp) { 
-               if (strcmp(avp[0], "id") == 0) {
-                       wpt_tmp->shortname = xstrdup(avp[1]);
-               }
-               avp+=2;
-       }
+       waypt_add(wpt_tmp);
 }
 
-static void
-tag_type(const char **attrv)
+void wpt_name_s(const char *args, const char **attrv)
 {
-       const char **avp = &attrv[0];
-       while (*avp) { 
-               if (strcmp(avp[0], "type") == 0) {
-                       wpt_tmp->icon_descr = xstrdup(avp[1]);
-               }
-               avp+=2;
-       }
+        const char **avp = &attrv[0];
+        while (*avp) {
+                if (0 == strcmp(avp[0], "id")) {
+                        wpt_tmp->shortname = xstrdup(avp[1]);
+                }
+                avp+=2;
+        }
 }
 
-static void
-tag_link(const char **attrv)
+void wpt_name(const char *args, const char **unused)
 {
-       const char **avp = &attrv[0];
-       while (*avp) { 
-               if (strcmp(avp[0], "text") == 0) {
-                       wpt_tmp->url_link_text = xstrdup(avp[1]);
-               }
-               avp+=2;
-       }
+       if (args) wpt_tmp->description = xstrdup(args);
 }
 
-static void
-geo_start(void *data, const char *el, const char **attr)
+void wpt_link_s(const char *args, const char **attrv)
 {
-
-       if (in_wpt) {
-               if (strcmp(el, "ele") == 0) {
-                       wpt_tmp->altitude = atoi(attr[1]);
-               }
-               else if (strcmp(el, "name") == 0) {
-                       tag_name(attr);
-               }
-               else if (strcmp(el, "coord") == 0) {
-                       tag_coord(attr);
-               }
-               else if (strcmp(el, "type") == 0) {
-                       tag_type(attr);
-               }
-       }
-
-       if (strcmp(el, "waypoint") == 0) {
-               wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1);
-               in_wpt++;
-       } else if (strcmp(el, "name") == 0) {
-               in_name++;
-       } else if (strcmp(el, "type") == 0) {
-               tag_type(attr);
-               in_type++;
-       } else if (strcmp(el, "link") == 0) {
-               tag_link(attr);
-               in_link++;
-       }
+        const char **avp = &attrv[0];
+        while (*avp) {
+                if (0 == strcmp(avp[0], "text")) {
+                        wpt_tmp->url_link_text = xstrdup(avp[1]);
+                }
+                avp+=2;
+        }
+}
+void wpt_link(const char *args, const char **attrv)
+{
+       wpt_tmp->url = xstrdup(args);
 }
 
-static void
-geo_end(void *data, const char *el)
+void wpt_type(const char *args, const char **unused)
 {
-       if (in_cdata) {
-               if (in_name) {
-                       wpt_tmp->description = xstrdup(cdatastr);
-               }
-               if (in_link) {
-                       wpt_tmp->url = xstrdup(cdatastr);
-               }
-               in_cdata--;
-               memset(cdatastr,0, MY_CBUF);
-       }
-       if (strcmp(el, "waypoint") == 0) {
-               waypt_add(wpt_tmp);
-               in_wpt--;
-       }
-       else if (strcmp(el, "name") == 0) {
-               in_name--;
-       }
-       else if (strcmp(el, "type") == 0) {
-               wpt_tmp->icon_descr_is_dynamic = 1;
-               wpt_tmp->icon_descr = xstrdup(typestr);
-               memset(typestr,0, MY_CBUF);
-               in_type--;
-       }
-       else if (strcmp(el, "link") == 0) {
-               in_link--;
-       }
+       wpt_tmp->icon_descr_is_dynamic = 1;
+       wpt_tmp->icon_descr = xstrdup(args);
 }
 
-static void
-geo_cdata(void *dta, const XML_Char *s, int len)
+void wpt_coord(const char *args, const char **attrv)
 {
-       char *estr;
-       if (in_name || in_link) {
-               estr = cdatastr + strlen(cdatastr);
-               memcpy(estr, s, len); 
-               in_cdata++;
-       }
-       if (in_type) {
-               estr = typestr + strlen(typestr);
-               memcpy(estr, s, len); 
-       }
+        const char **avp = &attrv[0];
+
+        while (*avp) {
+                if (strcmp(avp[0], "lat") == 0) {
+                        sscanf(avp[1], "%lf",
+                                &wpt_tmp->latitude);
+                }
+                else if (strcmp(avp[0], "lon") == 0) {
+                        sscanf(avp[1], "%lf",
+                                &wpt_tmp->longitude);
+                }
+                avp+=2;
+        }
 }
 
 void
 geo_rd_init(const char *fname)
 {
-       fd = xfopen(fname, "r", MYNAME);
-
-       psr = XML_ParserCreate(NULL);
-       if (!psr) {
-               fatal(MYNAME ":Cannot create XML parser\n");
-       }
-
-       XML_SetElementHandler(psr, geo_start, geo_end);
-       cdatastr = xcalloc(MY_CBUF,1);
-       typestr = xcalloc(MY_CBUF,1);
-       XML_SetCharacterDataHandler(psr, geo_cdata);
+       xml_init(fname, loc_map);
 }
 
 void
 geo_read(void)
 {
-       int len;
-       char buf[MY_CBUF];
-       
-       while ((len = fread(buf, 1, sizeof(buf), fd))) {
-               if (!XML_Parse(psr, buf, len, feof(fd))) {
-                       fatal(MYNAME ":Parse error at %d: %s\n", 
-                               XML_GetCurrentLineNumber(psr),
-                               XML_ErrorString(XML_GetErrorCode(psr)));
-               }
-       }
-
-       XML_ParserFree(psr);
+       xml_read();
 }
-
 #endif
 
 void
 geo_rd_deinit(void)
 {
-       if ( cdatastr ) {
-               xfree(cdatastr);
-       }
-       if ( typestr ) {
-               xfree(typestr);
-       }
-       fclose(fd);
+       xml_deinit();
 }
 
 void
diff --git a/gpsbabel/xmlgeneric.c b/gpsbabel/xmlgeneric.c
new file mode 100644 (file)
index 0000000..4e6324b
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+    Common utilities for XML-based formats.
+
+    Copyright (C) 2004 Robert Lipe, robertlipe@usa.net
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#include "defs.h"
+#include "xmlgeneric.h"
+
+#ifndef NO_EXPAT
+       #include <expat.h>
+       static XML_Parser psr;
+#endif
+
+static vmem_t current_tag;
+static vmem_t cdatastr;
+static FILE *ifd;
+static xg_tag_mapping *xg_tag_tbl;
+
+#define MY_CBUF 4096
+
+#define MYNAME "XML Reader"
+
+void
+write_xml_entity(FILE *ofd, const char *indent,
+                 const char *tag, const char *value)
+{
+        char *tmp_ent = xml_entitize(value);
+        fprintf(ofd, "%s<%s>%s</%s>\n", indent, tag, tmp_ent, tag);
+        xfree(tmp_ent);
+}
+
+void
+write_optional_xml_entity(FILE *ofd, const char *indent,
+                          const char *tag, const char *value)
+{
+        if (value && *value)
+                write_xml_entity(ofd, indent, tag, value);
+}
+
+
+/***********************************************************************
+ * These implement a simple interface for "generic" XML that
+ * maps reasonably close to  1:1 between XML tags and internal data
+ * structures.   
+ * 
+ * It doesn't work well for formats (like GPX) that really are "real"
+ * XML with extended namespaces and such, but it handles many simpler
+ * xml strains and insulates us from a lot of the grubbiness of expat.
+ */
+
+xg_callback *
+xml_tbl_lookup(const char *tag, xg_cb_type cb_type)
+{
+       xg_tag_mapping *tm;
+        for (tm = xg_tag_tbl; tm->tag_cb != NULL; tm++) {
+               if (0 == strcmp(tm->tag_name, tag) && (cb_type == tm->cb_type)) {
+                       return tm->tag_cb;
+               }
+       }
+       return NULL;
+}
+
+
+static void
+xml_start(void *data, const char *el, const char **attr)
+{
+       char *e;
+       char *ep;
+       xg_callback *cb;
+
+       vmem_realloc(&current_tag, strlen(current_tag.mem) + 2 + strlen(el));
+
+       e = current_tag.mem;
+        ep = e + strlen(e);
+        *ep++ = '/';
+        strcpy(ep, el);
+
+       memset(cdatastr.mem, 0, cdatastr.size);
+
+       cb = xml_tbl_lookup(e, cb_start);
+       if (cb) {
+               (*cb)(NULL, attr);
+       }
+}
+
+static void
+xml_cdata(void *dta, const XML_Char *s, int len)
+{
+       char *estr;
+       xg_callback *cb;
+
+       vmem_realloc(&cdatastr,  1 + len + strlen(cdatastr.mem));
+       estr = (char *) cdatastr.mem + strlen(cdatastr.mem);
+       memcpy(estr, s, len);
+       estr[len]  = 0;
+
+       cb = xml_tbl_lookup(current_tag.mem, cb_cdata);
+       if (cb) {
+               (*cb)(estr, NULL);
+       }
+}
+
+static void
+xml_end(void *data, const char *el)
+{
+       char *s = strrchr(current_tag.mem, '/');
+       xg_callback *cb;
+
+       if (strcmp(s + 1, el)) {
+               fprintf(stderr, "Mismatched tag %s\n", el);
+       }
+
+       cb = xml_tbl_lookup(current_tag.mem, cb_end);
+       if (cb) {
+               (*cb)(el, NULL);
+       }
+       *s = 0;
+}
+
+void xml_read(void)
+{
+       int len;
+       char buf[MY_CBUF];
+       
+       while ((len = fread(buf, 1, sizeof(buf), ifd))) {
+               if (!XML_Parse(psr, buf, len, feof(ifd))) {
+                       fatal(MYNAME ":Parse error at %d: %s\n",
+                               XML_GetCurrentLineNumber(psr),
+                               XML_ErrorString(XML_GetErrorCode(psr)));
+               }
+       }
+       XML_ParserFree(psr);
+       
+}
+
+void
+xml_init(const char *fname, xg_tag_mapping *tbl)
+{
+       ifd = xfopen(fname, "r", MYNAME);
+
+       current_tag = vmem_alloc(1,0);
+       *((char *)current_tag.mem) = '\0';
+
+       psr = XML_ParserCreate(NULL);
+       if (!psr) {
+               fatal(MYNAME ": Cannot create XML Parser\n");
+       }
+
+       cdatastr = vmem_alloc(1, 0);
+       *((char *)cdatastr.mem) = '\0';
+
+       xg_tag_tbl = tbl;
+
+       XML_SetElementHandler(psr, xml_start, xml_end);
+       XML_SetCharacterDataHandler(psr, xml_cdata);
+}
+
+void
+xml_deinit(void)
+{
+       vmem_free(&current_tag);
+       vmem_free(&cdatastr);
+}
+
+/******************************************/
diff --git a/gpsbabel/xmlgeneric.h b/gpsbabel/xmlgeneric.h
new file mode 100644 (file)
index 0000000..f01f2ee
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+    Header for our common utilities for XML-based formats.
+
+    Copyright (C) 2004 Robert Lipe, robertlipe@usa.net
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+
+
+typedef enum {
+       cb_start = 1,
+       cb_cdata,
+       cb_end,
+} xg_cb_type;
+
+typedef void (xg_callback) (const char *, const char **);
+
+typedef struct xg_tag_mapping {
+       xg_callback *tag_cb;
+       xg_cb_type cb_type;
+       const char *tag_name;
+} xg_tag_mapping;
+
+
+void write_xml_entity(FILE *ofd, const char *indent,
+                 const char *tag, const char *value);
+
+void write_optional_xml_entity(FILE *ofd, const char *indent,
+                 const char *tag, const char *value);
+
+void xml_init(const char *fname, xg_tag_mapping *tbl);
+void xml_read(void);
+void xml_deinit(void);